25.12.25 nextjs on-demand isr

마지막 수정일: 2025. 12. 24.

Problem

기존에는 time based로 작업됐음 25.01.30 ISR 적용 및 최적화 자세한 내용은 여기
60초마다 revalidate하게 설정했지만 생각보다 대기시간이 답답했고 너무 짧게 설정하자니 서버에 부담이라고 생각함
기존에도 on-demand 방식이 존재한다는 것은 알고 있었지만 보관 방법부터 trigger, scheduling까지 고려할 점들이 있었는데 이번에 aws 설정하면서 비용이 많이 내려가 바꾸기로 결정

해결 방법

고려해야할 점은 다음 3가지

  1. 어디에 저장할까(storage)
  2. 어떻게 감지할까(detection)
  3. 어떻게 ISR 서버를 re-build할까(revalidation)

Storage

일단 obsidian에서 지원하는 storage, plugin이어야한다.
먼저 plugin부터 살펴보면 크게 후보는 3가지

  1. obsidian sync
  2. remotely save
  3. obsidian git, git sync

1번은 공식이지만 유료, 3번은 너무 좋지만 모바일에서는 문제가 있다는 내용이 많아서 기각
원래 사용하던 remotely save를 그대로 쓰기로 함
물론 remotely save에도 여러 storage를 지원하지만 가장 눈여겨 볼만한 거는 icloud와 s3
나는 icloud가 꽉 찼지만 icloud를 안 쓰는 사람이면 무료로 어느정도 많이 사용해 볼만할 듯
하지만 나는 s3로

Detection & Revalidation

S3를 사용했기 때문에 같은 AWS 서비스를 사용하는 게 경험상 훨씬 편하다고 생각
S3 lambda에 trigger, code 등 여러가지를 한 번에 할 수 있어서 detection과 revalidation을 한 번에 할 수 있었음
구조는 다음과 같이 구현


현재 블로그에 사용되는 kyungbin, programming, side proejct 이 3개를 trigger로 잡았음
코드는 간단하게 다음과 같이 배포

JAVASCRIPT
export const handler = async event => {
  const records = event.Records || [];
  for (const r of records) {
    const key = decodeURIComponent(r.s3.object.key.replace(/\+/g, " "));

    await fetch("https://myexampleurl.com/api", {
      method: "POST",
      headers: {
        "content-type": "application/json",
      },
      body: JSON.stringify(key ? { key } : {}),
    });
  }
};

그리고 nextjs를 사용했기 때문에 같은 route로 api를 구현하여 배포했음

TYPESCRIPT
import { revalidatePath } from "next/cache";
import { NextRequest, NextResponse } from "next/server";

export async function POST(request: NextRequest) {
  try {
    const body = await request.json().catch(() => ({}));
    const path = body.path;

    if (path) {
      revalidatePath(path);
    } else {
      revalidatePath("/dot", "layout");
    }

    return NextResponse.json({
      revalidated: true,
      now: Date.now(),
      path: path || "all dot pages",
    });
  } catch (err) {
    return NextResponse.json(
      {
        message: "Error revalidating",
        error: err instanceof Error ? err.message : String(err),
      },
      { status: 500 }
    );
  }
}

성과

거의 바로 배포되는 환경을 구현해낼 수 있었음